package com.mitac.mcd.cs.mobiletracking.socketserver;


import java.beans.PropertyVetoException;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
import java.util.Hashtable;
import java.util.Properties;

import com.mitac.mcd.cs.mobiletracking.socketserver.util.BusinessUtil;
import com.mitac.mcd.cs.mobiletracking.socketserver.util.DBConnection;


public class MobileServer
{
	
    public static String IP;
    public static int PORT;
    public static String SERVER_SN;
    public static int timeout;
    public static int tcpSocketAutTimeout;
    public static int tcpSocketGpsuploadExpPacketCount;
    public static int tcpSocektGpsuploadHealthPolicyCount;
    public static int tcpSokcetMaxConnection;
    public static int memcacheLockKeyLockCounts;
    public static long memcacheLockKeyWaitTime;
    public static boolean enableCheckGpsuploadExpPacket;
    public static boolean enableMultiLoginMode;
    public static int notificationToClientDelayTime;
    public static int notificationToClientResendTime;
    public static int onlineCountLogInterval;
    public static double onlineCountThreshold;
    public static Hashtable<String, String> exceptionProperties = new Hashtable<String, String>();
    public static Hashtable<String, PrintStream> outputStreams = new Hashtable<String, PrintStream>();
    public static Hashtable<String, HealthCheck> healthCheckList = new Hashtable<String, HealthCheck>();
    public static Hashtable<String, String> uuidUseridList = new Hashtable<String, String>();
    public static Hashtable<String, String> useridUuidList = new Hashtable<String, String>();
    public static Hashtable<String, String[]> uuidGroupList = new Hashtable<String,String[]>();
    public static Hashtable<String, String[]> uuidTaskList = new Hashtable<String,String[]>();
    public static String ENCODING;
    public ServerSocket server;
    public static int SERVER_ID;
    public static final Properties ConfigProperties = new Properties();
    public static final Properties jdbcProperties = new Properties();
    public static int coordinatesBufferLength;
    public static Date starttime = null;
    private boolean _run = true;
    /**********************************************************/
    public static long KEY_LOCK_WAITING_COUNT=0;
    /**********************************************************/
    
    public MobileServer() throws IOException {
    	BusinessUtil.sLogger.info("******************************************************");
        BusinessUtil.sLogger.info("初始化系统参数开始...");
        String configFilePath = "./config.properties";//System.getProperty("user.dir") + "\\config.properties";
        BusinessUtil.sLogger.info("configFilePath:"+configFilePath);
        InputStream ConfigInputStream = new BufferedInputStream(new FileInputStream(configFilePath));
        //InputStream ConfigInputStream = getClass().getClassLoader().getResourceAsStream(proFilePath);
        ConfigProperties.load(ConfigInputStream);
        String jdbcFilePath = "./jdbc.properties";//System.getProperty("user.dir") + "\\jdbc.properties";
        BusinessUtil.sLogger.info("jdbcFilePath:"+jdbcFilePath);
        InputStream jdbcInputStream = new BufferedInputStream(new FileInputStream(jdbcFilePath));
        jdbcProperties.load(jdbcInputStream);
        //init db connection pool
        try {
			DBConnection.initAutConnection();
			DBConnection.initGPSDATAConnection();
		} catch (Exception e) {
			BusinessUtil.sLogger.error("数据库连接池初始化发生异常:"+e);
			BusinessUtil.sLogger.error("MobileServer启动失败...");
			return;
		}
        //获取到配置文件中设定的cache中设置item数组的设定长度值
        coordinatesBufferLength = Integer.parseInt(MobileServer.ConfigProperties.get("COORDINATE_BUFFER_LENGTH").toString());
        BusinessUtil.sLogger.info("获取到配置文件中设定的cache中设置item数组的设定长度值:"+coordinatesBufferLength);
        //获取到配置文件中设定的socket server IP
        IP = MobileServer.ConfigProperties.get("SOCKET_SERVER_IP").toString();
        BusinessUtil.sLogger.info("获取到配置文件中设定的socket server IP:"+IP);
        //获取到配置文件中设定的socket server PORT
        PORT = Integer.parseInt(MobileServer.ConfigProperties.get("SOCKET_SERVER_PORT").toString());
        BusinessUtil.sLogger.info("获取到配置文件中设定的socket server PORT:"+PORT);
        //获取配置文件中连接socket server 超时设置的值
        timeout = Integer.parseInt(MobileServer.ConfigProperties.get("SOCKET_SERVER_TIMEOUT").toString());
        BusinessUtil.sLogger.info("获取配置文件中连接socket server 超时设置的值:"+timeout+"s");
        //获取配置文件中获取第一笔aut或notification资料的时间
        tcpSocketAutTimeout = Integer.parseInt(MobileServer.ConfigProperties.get("TCP_SOCKET_AUT_TIMEOUT").toString());
        BusinessUtil.sLogger.info("获取配置文件中获取第一笔aut或notification资料的时间:"+tcpSocketAutTimeout+"s");
        //获取配置文件中在interval内check的buffer个数
        tcpSocketGpsuploadExpPacketCount = Integer.parseInt(MobileServer.ConfigProperties.get("TCP_SOCKET_GPSUPLOAD_EXP_PACKETCOUNT").toString());
        BusinessUtil.sLogger.info("获取配置文件中在interval内check的buffer个数:"+tcpSocketGpsuploadExpPacketCount);
        //获取配置文件中HealthCheck 策略個數
        tcpSocektGpsuploadHealthPolicyCount = Integer.parseInt(MobileServer.ConfigProperties.get("TCP_SOCKET_GPSUPLOAD_HEALTH_POLICY_COUNT").toString());
        BusinessUtil.sLogger.info("获取配置文件中HealthCheck 策略個數:"+tcpSocektGpsuploadHealthPolicyCount);
        //获取配置文件中最高client上限連線數
        tcpSokcetMaxConnection = Integer.parseInt(MobileServer.ConfigProperties.get("TCP_SOCKET_MAX_CONNECTION").toString());
        BusinessUtil.sLogger.info("获取配置文件中最高client上限連線數:"+tcpSokcetMaxConnection);
        //获去配置文件中是否允许对interval内上传data笔数做check
        enableCheckGpsuploadExpPacket = Boolean.parseBoolean(MobileServer.ConfigProperties.get("ENABLE_CHECK_GPSUPLOAD_EXP_PACKET").toString());
        BusinessUtil.sLogger.info("获取配置文件中是否允许对interval内上传data笔数做check:"+enableCheckGpsuploadExpPacket);
        //是否允许device以混合模式登录,包含login mode和be tracked mode
        enableMultiLoginMode = Boolean.parseBoolean(MobileServer.ConfigProperties.get("ENABLE_MULTI_LOGIN_MODE").toString());
        BusinessUtil.sLogger.info("是否允许device以混合模式登录,包含login mode和be tracked mode:"+enableMultiLoginMode);
        //访问memcache retry次数
        memcacheLockKeyLockCounts = Integer.parseInt(MobileServer.ConfigProperties.get("MEMCECHE_LOCKKEY_LOCK_COUNTS").toString());
        BusinessUtil.sLogger.info("访问memcache retry次数:"+memcacheLockKeyLockCounts);
        //memcache添加lock expiration
        memcacheLockKeyWaitTime = Long.parseLong(MobileServer.ConfigProperties.get("MEMCACHE_LOCKKEY_WAIT_TIME").toString());
        BusinessUtil.sLogger.info("memcache添加lock expiration:"+memcacheLockKeyWaitTime+"ms");
        //多久沒接收到Client 端對Notification 指令的回應 JSON 資料就重发指令，单位s
        notificationToClientDelayTime = Integer.parseInt(MobileServer.ConfigProperties.get("NOTIFICATION_TO_CLIENT_DELAYTIME").toString());
        BusinessUtil.sLogger.info("多久沒接收到Client 端對Notification 指令的回應 JSON 資料就重发指令，单位s:"+notificationToClientDelayTime);
        //多久沒接收到Client 端對Notification 指令的回應 JSON 資料就重发指令的重發次數.
        notificationToClientResendTime = Integer.parseInt(MobileServer.ConfigProperties.get("NOTIFICATION_TO_CLINET_RESENDTIME").toString());
        BusinessUtil.sLogger.info("多久沒接收到Client 端對Notification 指令的回應 JSON 資料就重发指令的重發次數:"+notificationToClientResendTime);
        //Log当前系统在线人数的时间间隔
        onlineCountLogInterval = Integer.parseInt(MobileServer.ConfigProperties.get("ONLINE_COUNT_LOG_INTERVAL").toString());
        BusinessUtil.sLogger.info("Log当前系统在线人数的时间间隔:"+onlineCountLogInterval);
        //Log当前系统在线人数的峰值警戒值设定比例
        onlineCountThreshold = Double.parseDouble(MobileServer.ConfigProperties.get("ONLINE_COUNT_THRESHOLD").toString());
        BusinessUtil.sLogger.info("Log当前系统在线人数的峰值警戒值设定比例:"+onlineCountThreshold);
        //获取配置文件中编码设置
        ENCODING = MobileServer.ConfigProperties.get("SOCKET_SERVER_ENCODING").toString();
        BusinessUtil.sLogger.info("获取配置文件中编码设置:"+ENCODING);
        //将DB中exceptionproperties的属性放入hashtable中
        //getExceptionProperties();
        //BusinessUtil.sLogger.info("完成将DB中exceptionproperties的属性放入hashtable中...");
        
        BusinessUtil.sLogger.info("初始化系统参数完成...");
        BusinessUtil.sLogger.info("******************************************************");
        //get server ID
        getServerID();
        //log server start record to db
        SERVER_SN = IP+":"+PORT;
        starttime = new Date();
        BusinessUtil.logServer(SERVER_ID,SERVER_SN);
        
        new CheckOnlineCount(this);
        
        listen();
    }
    
    private void getServerID() {
    	java.sql.Connection dbc = null;
        PreparedStatement pst = null;
        String sqlA = " select SERVER_ID from SERVERS_CONFIGURATION where SERVER_INTERNAL_IPADDRESS=? and SERVER_INTERNAL_PORT=? and SERVER_TYPE=? ";
        ResultSet rs = null;
        try {
        	dbc = DBConnection.getConnection("gpsdata");
			pst = dbc.prepareStatement(sqlA);
			pst.setString(1, IP);
			pst.setInt(2, PORT);
			pst.setInt(3, 1);
			rs = pst.executeQuery();
			while(rs.next()){
				SERVER_ID = rs.getInt("SERVER_ID");
			}
		} catch (SQLException e) {
			BusinessUtil.sLogger.error("getServerID() 发生异常:"+e);
		} catch (PropertyVetoException e) {
			BusinessUtil.sLogger.error("getServerID() 发生异常:"+e);
		}
		try
        {
			if(null!=rs) rs.close();
            dbc.close();
            pst.close();
        }catch(SQLException e)
        {
            e.printStackTrace();
        }
    
	}

	public void listen() {
        try {
        	// Create the ServerSocket
			server = new ServerSocket(PORT);
			// Tell the world we're ready to go
	        BusinessUtil.sLogger.info( "Listening on :"+server );
	        // Keep accepting connections forever
	        while (_run) {
	            Socket socket = server.accept();
	            BusinessUtil.sLogger.info("Connection from "+socket);
	            new MobileServerThread(this, socket);
	        }
		} catch (IOException e) {
			e.printStackTrace();
		}
    }
    
    /**
     * 将DB中exceptionproperties的属性放入hashtable中
     */
    public void getExceptionProperties(){
    	java.sql.Connection dbc = null;
        PreparedStatement pst = null;
        String sqlA = " select EXCEPTION_PROP_CODE,NOTE from EXCEPTIONPROPERTIES ";
        ResultSet rs = null;
        try {
        	dbc = DBConnection.getConnection("gpsdata");
			pst = dbc.prepareStatement(sqlA);
			rs = pst.executeQuery();
			while(rs.next()){
				exceptionProperties.put(rs.getString("EXCEPTION_PROP_CODE"), rs.getString("NOTE"));
			}
		} catch (SQLException e) {
			BusinessUtil.sLogger.error("getExceptionProperties() 发生异常:"+e);
		} catch (PropertyVetoException e) {
			BusinessUtil.sLogger.error("getExceptionProperties() 发生异常:"+e);
		}
		try
        {
			if(null!=rs) rs.close();
            dbc.close();
            pst.close();
        }catch(SQLException e)
        {
            e.printStackTrace();
        }
    }
    
    public void stopThread() {
        this._run = false;
    }
    
    public static void main(String args[]) throws IOException, InterruptedException{
        new MobileServer();
    }
}
